<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>待办事项管理系统</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
</head>
<body class="bg-gray-50 min-h-screen">
<!-- 导航栏 -->
<nav id="navbar" class="bg-white shadow-sm py-3 transition-all duration-300">
    <div class="container mx-auto px-4">
        <div class="flex justify-between h-16">
            <div class="flex items-center">
                <a href="/" class="flex items-center">
                    <i class="fa fa-check-square-o text-blue-600 text-2xl mr-2"></i>
                    <span class="font-bold text-xl text-gray-800">待办事项管理系统</span>
                </a>
            </div>

            <div class="flex items-center space-x-4">
                <!-- 导入导出按钮 -->
                <div class="flex items-center space-x-2">
                    <button id="export-todos" class="px-3 py-1.5 text-sm bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors">
                        <i class="fa fa-download mr-1"></i> 导出
                    </button>
                    <label for="import-todos" class="px-3 py-1.5 text-sm bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors cursor-pointer">
                        <i class="fa fa-upload mr-1"></i> 导入
                    </label>
                    <input type="file" id="import-todos" accept=".xlsx,.xls" class="hidden">
                </div>

                <!-- 管理员菜单 -->
                <div id="admin-menu" class="hidden">
                    <button id="admin-center-btn" class="px-3 py-1.5 text-sm bg-purple-500 text-white rounded-md hover:bg-purple-600 transition-colors">
                        <i class="fa fa-cog mr-1"></i> 管理中心
                    </button>
                </div>

                <!-- 未登录状态按钮 -->
                <div id="auth-buttons" class="hidden">
                    <button id="login-btn-main" class="px-3 py-1.5 text-sm bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors">
                        <i class="fa fa-sign-in mr-1"></i> 登录
                    </button>
                    <button id="register-btn-main" class="px-3 py-1.5 text-sm bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors">
                        <i class="fa fa-user-plus mr-1"></i> 注册
                    </button>
                </div>

                <!-- 用户菜单 -->
                <div id="user-menu" class="relative hidden">
                    <button id="user-menu-button" class="flex items-center text-sm font-medium text-gray-700 hover:text-gray-900">
                        <i class="fa fa-user-circle text-xl mr-1"></i>
                        <span id="username-display">用户名</span>
                        <i class="fa fa-chevron-down ml-1 text-xs"></i>
                    </button>
                    <div id="user-dropdown" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-10">
                        <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">个人资料</a>
                        <a href="#" id="tag-management-btn" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">标签管理</a>
                        <div class="border-t border-gray-100"></div>
                        <a href="#" id="logout-button" class="block px-4 py-2 text-sm text-red-600 hover:bg-gray-100">退出登录</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</nav>

<!-- 管理员视图 -->
<div id="admin-view" class="container mx-auto px-4 py-8 hidden">
    <div class="bg-white p-6 rounded-lg shadow-sm mb-8">
        <h2 class="text-lg font-semibold mb-4">管理员中心</h2>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
            <div>
                <h3 class="font-medium mb-2">用户管理</h3>
                <button id="manage-users-btn" class="px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700">
                    管理用户
                </button>
            </div>
            <div>
                <h3 class="font-medium mb-2">举报审核</h3>
                <button id="review-reports-btn" class="px-4 py-2 bg-yellow-600 text-white rounded-md hover:bg-yellow-700">
                    审核举报
                </button>
            </div>
        </div>
        <!-- 待审核待办事项列表 -->
        <div class="mt-6">
            <h3 class="font-medium mb-3">待审核待办事项</h3>
            <div id="admin-todo-list">
                <!-- 动态渲染待审核列表 -->
            </div>
        </div>
    </div>
</div>

<!-- 主内容区 -->
<main class="container mx-auto px-4 py-8">
    <!-- 未登录视图 -->
    <div id="unauthenticated-view" class="hidden">
        <div class="bg-white p-8 rounded-lg shadow-sm text-center">
            <i class="fa fa-lock text-5xl text-gray-400 mb-4"></i>
            <h2 class="text-xl font-bold text-gray-800 mb-2">请先登录</h2>
            <p class="text-gray-600 mb-6">登录后即可管理您的待办事项</p>
            <div class="flex justify-center space-x-4">
                <button id="login-btn" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
                    <i class="fa fa-sign-in mr-1"></i> 登录
                </button>
                <button id="register-btn" class="px-6 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors">
                    <i class="fa fa-user-plus mr-1"></i> 注册
                </button>
            </div>
        </div>
    </div>

    <!-- 已登录视图 -->
    <div id="authenticated-view" class="hidden">
        <!-- 页面标题 -->
        <div class="mb-8">
            <h1 class="text-2xl font-bold text-gray-800">我的待办事项</h1>
            <div class="mb-4">
                <a href="tag-management.html" class="inline-flex items-center px-4 py-2 text-blue-600 hover:text-blue-800">
                    <i class="fa fa-tags mr-1"></i> 标签管理
                </a>
            </div>
            <p class="text-gray-600 mt-1">管理您的日常任务和待办清单</p>
        </div>

        <!-- 添加待办事项表单 -->
        <div class="bg-white p-6 rounded-lg shadow-sm mb-8">
            <h2 class="text-lg font-semibold mb-4">添加新的待办事项</h2>
            <form id="add-todo-form" class="flex flex-col md:flex-row gap-4">
                <div class="flex-1 flex flex-col gap-4">
                    <!-- 标题输入框 -->
                    <input
                            id="todo-title"
                            class="px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
                            placeholder="输入任务标题（必填）..."

                    >
                    <textarea
                            id="todo-content"
                            class="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
                            rows="3"
                            placeholder="输入任务内容..."

                    ></textarea>
                    <!-- 到期时间 -->
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">到期时间</label>
                        <input type="datetime-local" id="todo-due-date" class="w-full px-4 py-2 border border-gray-300 rounded-md">
                    </div>
                    <!-- 标签选择 -->
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">标签</label>
                        <div id="add-todo-tags" class="flex flex-wrap gap-2 mb-2">
                            <!-- 已选标签会动态添加 -->
                        </div>
                        <div id="add-available-tags" class="flex flex-wrap gap-2">
                            <!-- 可选标签会动态添加 -->
                        </div>
                        <a href="tag-management.html" class="text-sm text-blue-600 mt-1 inline-block">管理标签</a>
                    </div>
                </div>
                <div class="flex flex-col gap-2">
                    <select id="todo-status" class="px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
                        <option value="pending">待完成</option>
                        <option value="completed">已完成</option>
                    </select>
                    <button type="submit" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
                        <i class="fa fa-plus mr-1"></i> 添加
                    </button>
                </div>
            </form>
        </div>

        <!-- 公开待办事项区域 -->
        <div class="bg-white rounded-lg shadow-sm overflow-hidden mt-6">
            <div class="p-6 border-b border-gray-200">
                <h2 class="text-lg font-semibold">公开任务列表</h2>
            </div>
            <div id="public-todo-list" class="divide-y divide-gray-200">
                <!-- 公开待办事项将在这里渲染 -->
            </div>
        </div>

        <!-- 待办事项列表 -->
        <div class="bg-white rounded-lg shadow-sm overflow-hidden">
            <div class="p-6 border-b border-gray-200">
                <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
                    <h2 class="text-lg font-semibold">任务列表</h2>
                    <div class="flex items-center w-full sm:w-auto">
                        <span class="text-sm text-gray-600 mr-2">筛选：</span>
                        <div class="flex border rounded-md overflow-hidden flex-1 sm:flex-auto">
                            <button id="filter-all" class="flex-1 px-3 py-1 bg-primary text-white">全部</button>
                            <button id="filter-pending" class="flex-1 px-3 py-1 bg-gray-200 text-gray-700 hover:bg-gray-300">待完成</button>
                            <button id="filter-completed" class="flex-1 px-3 py-1 bg-gray-200 text-gray-700 hover:bg-gray-300">已完成</button>
                        </div>
                        <span class="ml-4 text-sm text-gray-600">已完成: <span id="todo-count">0/0</span></span>
                    </div>
                </div>
            </div>

            <!-- 待办事项列表内容 -->
            <div id="todos-list" class="divide-y divide-gray-200">
                <!-- 待办事项项会通过JS动态生成 -->
            </div>

            <!-- 空状态 -->
            <div id="empty-state" class="p-12 text-center hidden">
                <div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-gray-100 mb-4">
                    <i class="fa fa-inbox text-gray-400 text-2xl"></i>
                </div>
                <h3 class="text-lg font-medium text-gray-900 mb-1">暂无待办事项</h3>
                <p class="text-gray-500">添加您的第一个待办事项，开始高效管理您的任务吧！</p>
            </div>

            <!-- 加载状态 -->
            <div id="loading-state" class="p-12 text-center hidden">
                <div class="inline-block animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500 mb-4"></div>
                <p class="text-gray-500">加载中...</p>
            </div>
        </div>
    </div>
</main>

<!-- 分享模态框 -->
<div id="share-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-md">
        <h3 class="text-xl font-bold mb-4">分享待办事项</h3>
        <div class="mb-4">
            <p class="text-gray-600 mb-2">公开访问链接：</p>
            <div class="flex">
                <input type="text" id="share-link" class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none" readonly>
                <button id="copy-link" class="px-4 py-2 bg-blue-600 text-white rounded-r-md hover:bg-blue-700 transition-colors">
                    复制
                </button>
            </div>
        </div>
        <p class="text-sm text-gray-500 mb-4">任何人都可以通过此链接查看该待办事项，无需登录</p>
        <button id="close-share" class="w-full px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
            关闭
        </button>
    </div>
</div>

<!-- 编辑模态框 -->
<div id="edit-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-lg">
        <h3 class="text-xl font-bold mb-4">编辑待办事项</h3>
        <form id="edit-todo-form">
            <input type="hidden" id="edit-todo-id">
            <div class="mb-4">
                <input
                        id="edit-todo-title"
                        class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                        placeholder="任务标题（必填）..."

                >
            </div>
            <div class="mb-4">
                <textarea
                        id="edit-todo-content"
                        class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                        rows="3"

                ></textarea>
            </div>
            <div class="mb-4">
                <label class="block text-sm font-medium text-gray-700 mb-1">到期时间</label>
                <input type="datetime-local" id="edit-todo-due-date" class="w-full px-4 py-2 border border-gray-300 rounded-md">
            </div>
            <!-- 标签选择 -->
            <div class="mb-4">
                <label class="block text-sm font-medium text-gray-700 mb-1">标签</label>
                <div id="edit-selected-tags" class="flex flex-wrap gap-2 mb-2">
                    <!-- 已选标签会动态添加 -->
                </div>
                <div id="edit-available-tags" class="flex flex-wrap gap-2">
                    <!-- 可选标签会动态添加 -->
                </div>
                <a href="tag-management.html" class="text-sm text-blue-600 mt-1 inline-block">管理标签</a>
            </div>
            <div class="mb-4">
                <select id="edit-todo-status" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
                    <option value="pending">待完成</option>
                    <option value="completed">已完成</option>
                </select>
            </div>
            <div class="flex justify-end gap-2">
                <button type="button" id="cancel-edit" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
                    取消
                </button>
                <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
                    保存
                </button>
            </div>
        </form>
    </div>
</div>

<!-- 确认删除模态框 -->
<div id="delete-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-md">
        <h3 class="text-xl font-bold mb-2">确认删除</h3>
        <p class="text-gray-600 mb-4">您确定要删除这个待办事项吗？此操作无法撤销。</p>
        <input type="hidden" id="delete-todo-id">
        <div class="flex justify-end gap-2">
            <button id="cancel-delete" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
                取消
            </button>
            <button id="confirm-delete" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors">
                删除
            </button>
        </div>
    </div>
</div>

<!-- 举报模态框 -->
<div id="report-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-md">
        <h3 class="text-xl font-bold mb-4">举报待办事项</h3>
        <p class="text-gray-600 mb-4">请说明举报原因：</p>
        <input type="hidden" id="report-todo-id">
        <textarea id="report-reason" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent mb-4" rows="3" placeholder="请输入举报原因..." required></textarea>
        <div class="flex justify-end gap-2">
            <button id="cancel-report" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
                取消
            </button>
            <button id="confirm-report" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors">
                提交举报
            </button>
        </div>
    </div>
</div>

<!-- 回复模态框（支持楼中楼） -->
<div id="reply-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-md">
        <h3 class="text-xl font-bold mb-4" id="reply-modal-title">添加回复</h3>
        <input type="hidden" id="reply-todo-id">
        <input type="hidden" id="reply-parent-id" value=""> <!-- 用于楼中楼回复 -->
        <textarea id="reply-content" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent mb-4" rows="3" placeholder="请输入回复内容..." required></textarea>
        <div class="flex justify-end gap-2">
            <button id="cancel-reply" class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
                取消
            </button>
            <button id="confirm-reply" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
                提交回复
            </button>
        </div>
    </div>
</div>

<!-- 用户管理模态框 -->
<div id="user-management-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-lg p-6 w-full max-w-2xl max-h-[80vh] overflow-y-auto">
        <h3 class="text-xl font-bold mb-4">用户管理</h3>
        <div id="users-list" class="space-y-4">
            <!-- 用户列表将通过JS动态生成 -->
        </div>
        <button id="close-user-modal" class="mt-4 px-4 py-2 border border-gray-300 rounded-md">
            关闭
        </button>
    </div>
</div>

<!-- 通知容器 -->
<div id="notification" class="fixed bottom-4 right-4 px-4 py-3 rounded-md shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 z-50"></div>

<script>
    // 全局状态
    const state = {
        todos: [],
        filteredTodos: [],
        publicTodos: [],
        currentFilter: 'all',
        currentUser: null,
        apiBaseUrl: 'http://localhost:8080',
        isRefreshingToken: false, // 添加令牌刷新状态
        refreshTimeout: null // 用于清除定时器
    };

    // DOM元素 - 确保所有元素在HTML中存在
    const elements = {
        authButtons: document.getElementById('auth-buttons'),
        userMenu: document.getElementById('user-menu'),
        adminMenu: document.getElementById('admin-menu'),
        adminView: document.getElementById('admin-view'),
        usernameDisplay: document.getElementById('username-display'),
        unauthenticatedView: document.getElementById('unauthenticated-view'),
        authenticatedView: document.getElementById('authenticated-view'),
        todoList: document.getElementById('todos-list'),
        emptyState: document.getElementById('empty-state'),
        todoCount: document.getElementById('todo-count'),
        addTodoForm: document.getElementById('add-todo-form'),
        todoContent: document.getElementById('todo-content'),
        editTodoModal: document.getElementById('edit-modal'),
        editTodoForm: document.getElementById('edit-todo-form'),
        notification: document.getElementById('notification'),
        filterButtons: {
            all: document.getElementById('filter-all'),
            pending: document.getElementById('filter-pending'),
            completed: document.getElementById('filter-completed')
        }
    };

    // 添加令牌检查函数
    function checkTokenExpiration() {
        const token = localStorage.getItem('token');
        const expiresAt = localStorage.getItem('tokenExpiresAt');
        const refreshToken = localStorage.getItem('refreshToken');

        // 如果没有刷新令牌，直接返回需要刷新
        if (!refreshToken) {
            return true;
        }

        if (!token || !expiresAt) {
            return false;
        }

        const now = new Date().getTime();
        const isExpired = now > parseInt(expiresAt);
        const isAboutToExpire = (parseInt(expiresAt) - now) < 300000; // 5分钟内

        // 检查刷新令牌是否即将在1天内过期（提前24小时开始尝试刷新）
        const loginTime = localStorage.getItem('loginTime');
        const refreshTokenExpiry = 604800000; // 7天，与后端保持一致
        const isRefreshTokenAboutToExpire = loginTime &&
            (now - parseInt(loginTime) > (refreshTokenExpiry - 86400000));

        return isExpired || isAboutToExpire || isRefreshTokenAboutToExpire;
    }

    // 刷新令牌函数
    async function refreshToken() {
        if (state.isRefreshingToken) {
            return; // 防止重复刷新
        }

        state.isRefreshingToken = true;
        try {
            const response = await fetch(`${state.apiBaseUrl}/auth/refresh`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    refreshToken: localStorage.getItem('refreshToken')
                })
            });

            if (response.ok) {
                const result = await response.json();
                const expiresAt = new Date().getTime() + 86400000;
                localStorage.setItem('token', result.accessToken);
                localStorage.setItem('tokenExpiresAt', expiresAt);
                // 刷新成功时更新登录时间
                localStorage.setItem('loginTime', new Date().getTime().toString());
                return true;
            } else {
                // 刷新失败，清除本地存储并重定向到登录
                localStorage.clear();
                window.location.href = '/login.html';
                showNotification('登录已过期，请重新登录', 'error');
                return false;
            }
        } catch (error) {
            console.error('令牌刷新失败:', error);
            localStorage.clear();
            window.location.href = '/login.html';
            return false;
        } finally {
            state.isRefreshingToken = false;
        }
    }

    // 设置定期检查令牌
    function setupTokenChecker() {
        if (state.refreshTimeout) {
            clearInterval(state.refreshTimeout);
        }

        // 每15分钟检查一次（缩短检查间隔）
        state.refreshTimeout = setInterval(() => {
            if (checkTokenExpiration()) {
                refreshToken();
            }
        }, 900000); // 15分钟 = 900000毫秒
    }

    // 添加请求拦截器功能
    async function fetchWithToken(url, options = {}) {
        // 检查令牌是否需要刷新
        if (checkTokenExpiration()) {
            const refreshed = await refreshToken();
            if (!refreshed) {
                return Promise.reject(new Error('令牌过期'));
            }
        }

        // 添加令牌到请求头
        const headers = {
            ...options.headers,
            'Authorization': `Bearer ${localStorage.getItem('token')}`
        };

        return fetch(url, {
            ...options,
            headers
        });
    }

    // 工具函数 - 显示通知
    function showNotification(message, type = 'success') {
        const notification = elements.notification;
        notification.textContent = message;
        notification.className = 'fixed bottom-4 right-4 px-4 py-3 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 z-50';

        if (type === 'success') {
            notification.classList.add('bg-green-50', 'text-green-800', 'border', 'border-green-200');
        } else if (type === 'error') {
            notification.classList.add('bg-red-50', 'text-red-800', 'border', 'border-red-200');
        } else if (type === 'info') {
            notification.classList.add('bg-blue-50', 'text-blue-800', 'border', 'border-blue-200');
        }

        // 3秒后隐藏
        setTimeout(() => {
            notification.classList.remove('translate-y-0', 'opacity-100');
            notification.classList.add('translate-y-20', 'opacity-0');
        }, 3000);
    }

    // 检查用户是否登录
    function checkAuth() {
        const token = localStorage.getItem('token');
        const username = localStorage.getItem('username');
        const userId = localStorage.getItem('userId');
        const isAdmin = localStorage.getItem('isAdmin') === 'true';

        if (isAdmin) {
            document.getElementById('admin-menu').classList.remove('hidden');
            document.getElementById('admin-view').classList.remove('hidden');
        }

        if (token && username && userId) {
            state.currentUser = {
                username,
                token,
                userId: parseInt(userId),
                isAdmin: isAdmin
            };
            renderAuthState();
            fetchTodos();
            loadUserTags(); // 加载用户标签
            startExpirationChecker(); // 启动到期检查器
            // 如果是管理员，获取管理员数据
            if (isAdmin) {
                fetchAllTodosForAdmin();
            }
        } else {
            state.currentUser = null;
            renderAuthState();
        }
    }

    // 渲染认证状态
    function renderAuthState() {
        if (state.currentUser) {
            // 已登录状态
            elements.authButtons.classList.add('hidden');
            elements.userMenu.classList.add('hidden');
            elements.usernameDisplay.textContent = state.currentUser.username;
            elements.unauthenticatedView.classList.add('hidden');
            elements.authenticatedView.classList.remove('hidden');
            // 管理员视图显示逻辑
            if (state.currentUser.isAdmin) {
                elements.adminView.classList.remove('hidden');
                elements.adminMenu.classList.remove('hidden');
            } else {
                elements.adminView.classList.add('hidden');
                elements.adminMenu.classList.remove('hidden');
            }
        } else {
            // 未登录状态
            elements.authButtons.classList.remove('hidden');
            elements.userMenu.classList.add('hidden');
            elements.unauthenticatedView.classList.remove('hidden');
            elements.authenticatedView.classList.add('hidden');
            elements.adminView.classList.add('hidden');
            elements.adminMenu.classList.add('hidden');
        }
    }

    // 获取Todo
    async function fetchTodos() {
        try {
            const { token, userId } = state.currentUser || {};
            if (!token || !userId) {
                showNotification('未登录，请先登录', 'error');
                return;
            }

            const response = await fetch(`${state.apiBaseUrl}/todos/${userId}`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });

            if (!response.ok) {
                const error = await response.text().catch(() => '获取任务失败');
                throw new Error(error || '获取任务失败');
            }

            let todos = await response.json();
            // 为每个待办事项初始化回复数组
            todos = todos.map(todo => ({
                ...todo,
                replies: [] // 先初始化为空数组
            })).sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));

            // 为每个todo获取评论
            for (let todo of todos) {
                try {
                    const commentsResponse = await fetch(`${state.apiBaseUrl}/comments/todo/${todo.id}`, {
                        headers: { 'Authorization': `Bearer ${token}` }
                    });
                    if (commentsResponse.ok) {
                        // 获取带用户信息的评论
                        todo.replies = await commentsResponse.json();
                    }
                } catch (error) {
                    console.error(`获取待办事项 ${todo.id} 的评论失败:`, error);
                }
            }

            // 更新状态并应用筛选
            state.todos = todos;
            applyFilter();
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error fetching todos:', error);
        }
    }
    async function submitReply() {
        const todoId = document.getElementById('reply-todo-id').value;
        const parentId = document.getElementById('reply-parent-id').value;
        const content = document.getElementById('reply-content').value;

        try {
            const response = await fetchWithToken(`${state.apiBaseUrl}/comments`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ todoId, content, parentId: parentId || null })
            });

            if (response.ok) {
                // 关键：重新加载对应待办事项的评论
                const isPublicTodo = state.publicTodos.some(t => t.id == todoId);
                if (isPublicTodo) {
                    fetchPublicTodos(); // 重新加载公开待办事项
                } else {
                    fetchTodos(); // 重新加载个人待办事项
                }
                document.getElementById('reply-modal').classList.add('hidden');
            }
        } catch (error) {
            console.error('提交回复失败:', error);
        }
    }

    // 获取所有Todo
    async function fetchAllTodosForAdmin() {
        if (!state.currentUser?.isAdmin) return;

        try {
            const response = await fetch(`${state.apiBaseUrl}/todos/admin/all`, {
                headers: { 'Authorization': `Bearer ${state.currentUser.token}` }
            });

            if (!response.ok) throw new Error('获取所有待办事项失败');
            const todos = await response.json();
            state.allTodos = todos; // 单独存储管理员视图的待办事项
            renderAdminTodoList(); // 渲染管理员的待办列表
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }

    // 审核待办事项
    async function reviewTodo(todoId, status) {
        if (!state.currentUser?.isAdmin) return;

        try {
            const params = new URLSearchParams();
            params.append('status', status);
            const response = await fetch(`${state.apiBaseUrl}/todos/admin/review/${todoId}?${params.toString()}`, {
                method: 'PATCH',
                headers: {
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
            });

            if (!response.ok) throw new Error('审核操作失败');
            showNotification('审核已完成');
            await fetchAllTodosForAdmin(); // 重新加载列表
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }

    // 渲染管理员待办列表
    function renderAdminTodoList() {
        const adminTodoContainer = document.getElementById('admin-todo-list');
        if (!adminTodoContainer) return;

        adminTodoContainer.innerHTML = state.allTodos.map(todo => `
        <div class="border-b p-4">
            <h3 class="font-medium">${todo.title}</h3>
            <p class="text-sm text-gray-600">${todo.content}</p>
            <div class="mt-2 flex items-center gap-2">
                <span class="text-xs px-2 py-1 rounded ${getReviewStatusClass(todo.reviewStatus)}">
                    ${getReviewStatusText(todo.reviewStatus)}
                </span>
                <div class="ml-auto flex gap-2">
                    <button onclick="reviewTodo(${todo.id}, 'approved')" class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">
                        通过
                    </button>
                    <button onclick="reviewTodo(${todo.id}, 'rejected')" class="text-xs bg-red-100 text-red-800 px-2 py-1 rounded">
                        拒绝
                    </button>
                </div>
            </div>
        </div>
    `).join('');
    }

    // 辅助函数：获取审核状态样式
    function getReviewStatusClass(status) {
        switch(status) {
            case 'pending': return 'bg-yellow-100 text-yellow-800';
            case 'approved': return 'bg-green-100 text-green-800';
            case 'rejected': return 'bg-red-100 text-red-800';
            default: return 'bg-gray-100 text-gray-800';
        }
    }

    // 辅助函数：获取审核状态文本
    function getReviewStatusText(status) {
        switch(status) {
            case 'pending': return '待审核';
            case 'approved': return '已通过';
            case 'rejected': return '已拒绝';
            default: return '未知状态';
        }
    }

    // 应用筛选
    function applyFilter() {
        switch (state.currentFilter) {
            case 'pending':
                state.filteredTodos = state.todos.filter(todo => todo.status === 'pending');
                break;
            case 'completed':
                state.filteredTodos = state.todos.filter(todo => todo.status === 'completed');
                break;
            default:
                state.filteredTodos = [...state.todos];
        }
        renderTodoList();
        updateTodoCount();
    }

    // 更新任务计数
    function updateTodoCount() {
        const total = state.todos.length;
        const completed = state.todos.filter(todo => todo.status === 'completed').length;
        elements.todoCount.textContent = `${completed}/${total}`;
    }

    // 渲染Todo列表
    function renderTodoList() {
        const { todoList, emptyState } = elements;
        todoList.innerHTML = '';

        if (state.filteredTodos.length === 0) {
            emptyState.classList.remove('hidden');
            return;
        }

        emptyState.classList.add('hidden');

        state.filteredTodos.forEach(todo => {
            const todoItem = document.createElement('div');
            todoItem.className = 'p-6 hover:bg-gray-50 transition-colors border-b border-gray-100';
            todoItem.dataset.id = todo.id;

            const createdAt = new Date(todo.createdAt).toLocaleString();

            // 确保标题存在，避免显示undefined
            const displayTitle = todo.title || '无标题';

            // 构建回复HTML
            let repliesHtml = '';
            if (todo.replies && todo.replies.length > 0) {
                repliesHtml = `
        <div class="mt-4 pl-4 border-l-2 border-gray-200">
            <h4 class="text-sm font-medium text-gray-700 mb-2">回复 (${todo.replies.length})</h4>
            ${renderComments(todo.replies)}
        </div>
    `;
            }

            todoItem.innerHTML = `
            <div class="flex justify-between items-start">
                <div class="flex-1">
                    <div class="flex items-center mb-2">
                        <span class="px-2 py-0.5 text-xs rounded-full ${todo.status === 'completed' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'}">
                            ${todo.status === 'completed' ? '已完成' : '待完成'}
                        </span>
                        <span class="text-sm text-gray-500 ml-2">${createdAt}</span>
                    </div>
                    <!-- 显示标题 -->
                    <h3 class="text-gray-900 font-medium mb-1 ${todo.status === 'completed' ? 'line-through' : ''}">${displayTitle}</h3>
                    <!-- 显示内容 -->
                    <p class="text-gray-700 ${todo.status === 'completed' ? 'line-through text-gray-500' : ''}">${todo.content}</p>
                    ${todo.deadline ? `
                    <div class="text-xs text-gray-500 mt-2">
                        截止时间: ${new Date(todo.deadline).toLocaleString()}
                        ${new Date(todo.deadline) < new Date() ?
                                '<span class="text-red-500 ml-2">已过期</span>' :
                                new Date(todo.deadline) - new Date() < 24*60*60*1000 ?
                                    '<span class="text-amber-500 ml-2">即将到期</span>' : ''
                            }
                    </div>
                     ` : ''}
                    <!-- 显示标签 -->
                    ${todo.tagIds && todo.tagIds.length > 0 ? `
                    <div class="flex flex-wrap gap-1 mt-2">
                        ${todo.tagIds.map(tagId => {
                                    // 通过ID查找名称，找不到时显示"未知标签"
                                    const tagName = tagIdToName[tagId] || `未知标签(${tagId})`;
                                    return `
                            <span class="px-2 py-0.5 text-xs bg-blue-100 text-blue-800 rounded-full">
                                ${tagName}
                            </span>
                            `;
                                }).join('')}
                    </div>
                    ` : ''}

                    <!-- 回复区域 -->
                    ${repliesHtml}

                    <!-- 回复按钮 -->
                    <button class="mt-2 text-sm text-blue-600 hover:text-blue-800 reply-btn" data-id="${todo.id}">
                        <i class="fa fa-reply mr-1"></i> 添加回复
                    </button>
                </div>
                <div class="flex items-center space-x-2 ml-4">
                    <button class="p-2 text-blue-500 hover:text-blue-700 hover:bg-blue-50 rounded-full transition-colors edit-todo-btn" title="编辑" data-id="${todo.id}">
                        <i class="fa fa-pencil"></i>
                    </button>
                    <button class="p-2 status-toggle-btn ${todo.status === 'completed' ? 'text-yellow-500 hover:text-yellow-700 hover:bg-yellow-50' : 'text-green-500 hover:text-green-700 hover:bg-green-50'} rounded-full transition-colors" title="${todo.status === 'completed' ? '标记为未完成' : '标记为完成'}" data-id="${todo.id}">
                        <i class="${todo.status === 'completed' ? 'fa fa-undo' : 'fa fa-check'}"></i>
                    </button>
                    <button class="p-2 text-orange-500 hover:text-orange-700 hover:bg-orange-50 rounded-full transition-colors share-todo-btn" title="分享" data-id="${todo.id}">
                        <i class="fa fa-share-alt"></i>
                    </button>
                    <button class="p-2 text-red-500 hover:text-red-700 hover:bg-red-50 rounded-full transition-colors report-todo-btn" title="举报" data-id="${todo.id}">
                        <i class="fa fa-flag"></i>
                    </button>
                    <button class="p-2 text-red-500 hover:text-red-700 hover:bg-red-50 rounded-full transition-colors delete-todo-btn" title="删除" data-id="${todo.id}">
                        <i class="fa fa-trash"></i>
                    </button>
                </div>
            </div>
        `;

            todoList.appendChild(todoItem);
        });

        // 重新绑定事件
        bindTodoEvents();
    }

    // 处理编辑点击
    async function handleEditClick(e) {
        const id = parseInt(e.currentTarget.dataset.id);
        const todo = state.todos.find(t => t.id === id);
        if (!todo) return;

        document.getElementById('edit-todo-id').value = id;
        document.getElementById('edit-todo-title').value = todo.title;
        document.getElementById('edit-todo-content').value = todo.content;
        document.getElementById('edit-todo-status').value = todo.status;
        document.getElementById('edit-todo-due-date').value = todo.deadline
            ? new Date(todo.deadline).toISOString().slice(0, 16)
            : '';

        // 清空并添加当前标签
        const selectedTagsContainer = document.getElementById('edit-selected-tags');
        selectedTagsContainer.innerHTML = '';
        if (todo.tags && todo.tags.length) {
            todo.tags.forEach(tag => {
                // 使用与添加任务一致的 addSelectedTag 方法
                addSelectedTag(tag, 'edit'); // 确保第二个参数对应正确的容器前缀
            });
        }
        renderAvailableTags('edit-available-tags', 'edit-selected-tags');
        document.getElementById('edit-modal').classList.remove('hidden');
    }

    // 处理状态变更
    async function handleStatusChange(e) {
        const id = parseInt(e.currentTarget.dataset.id);
        const todo = state.todos.find(t => t.id === id);
        if (!todo) return;

        const newStatus = todo.status === 'pending' ? 'completed' : 'pending';
        try {
            const response = await fetch(`${state.apiBaseUrl}/todos/${id}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify({ ...todo, status: newStatus })
            });

            if (!response.ok) throw new Error('更新状态失败');

            todo.status = newStatus;
            applyFilter();
            showNotification('任务状态已更新');
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error updating status:', error);
        }
    }

    // 渲染可选标签（适配添加和编辑任务场景）
    function renderAvailableTags() {
        // 处理添加任务的标签容器
        const addAvailableContainer = document.getElementById('add-available-tags');
        // 处理编辑任务的标签容器
        const editAvailableContainer = document.getElementById('edit-available-tags');

        // 清空两个容器（保留"新标签"按钮的逻辑已移除，统一通过动态生成处理）
        if (addAvailableContainer) addAvailableContainer.innerHTML = '';
        if (editAvailableContainer) editAvailableContainer.innerHTML = '';

        // 如果没有标签数据则返回
        if (!state.userTags || state.userTags.length === 0) return;

        // 获取已选中的标签ID（分别处理添加和编辑场景）
        const addSelectedTagIds = addAvailableContainer
            ? [...document.getElementById('add-todo-tags').children].map(el => parseInt(el.dataset.tagId))
            : [];

        const editSelectedTagIds = editAvailableContainer
            ? [...document.getElementById('edit-selected-tags').children].map(el => parseInt(el.dataset.tagId))
            : [];

        // 为添加任务场景渲染可选标签
        if (addAvailableContainer) {
            state.userTags.forEach(tag => {
                // 跳过已选中的标签
                if (addSelectedTagIds.includes(tag.id)) return;

                const tagBtn = document.createElement('button');
                tagBtn.type = 'button';
                tagBtn.className = 'px-2 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200 transition-colors';
                tagBtn.dataset.tagId = tag.id; // 确保使用 data-tag-id
                tagBtn.textContent = tag.name;
                tagBtn.addEventListener('click', () => addSelectedTag(tag, 'add')); // 点击后调用 addSelectedTag
                addAvailableContainer.appendChild(tagBtn);
            });
        }

        // 为编辑任务场景渲染可选标签
        if (editAvailableContainer) {
            state.userTags.forEach(tag => {
                // 跳过已选中的标签
                if (editSelectedTagIds.includes(tag.id)) return;

                const tagBtn = document.createElement('button');
                tagBtn.type = 'button'; // 添加这一行
                tagBtn.className = 'px-2 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200 transition-colors';
                tagBtn.dataset.tagId = tag.id;
                tagBtn.textContent = tag.name;
                tagBtn.addEventListener('click', () => addSelectedTag(tag, 'edit'));
                editAvailableContainer.appendChild(tagBtn);
            });
        }
    }

    // 处理删除点击
    function handleDeleteClick(e) {
        const id = parseInt(e.currentTarget.dataset.id);
        document.getElementById('delete-todo-id').value = id;
        document.getElementById('delete-modal').classList.remove('hidden');
    }

    // 处理举报点击
    function handleReportClick(e) {
        const id = parseInt(e.currentTarget.dataset.id);
        document.getElementById('report-todo-id').value = id;
        document.getElementById('report-reason').value = '';
        document.getElementById('report-modal').classList.remove('hidden');
    }

    // 处理分享点击
    function handleShareClick(e) {
        const id = parseInt(e.currentTarget.dataset.id);
        const todo = state.todos.find(t => t.id === id);
        if (todo) {
            document.getElementById('share-link').value = `${window.location.origin}/share.html?id=${id}`;
            document.getElementById('share-modal').classList.remove('hidden');
        }
    }

    // 添加辅助函数
    function formatDateTime(dateString) {
        const date = new Date(dateString);
        return date.toLocaleString();
    }

    function isExpired(dateString) {
        return new Date(dateString) < new Date();
    }

    function isUpcoming(dateString) {
        const now = new Date();
        const dueDate = new Date(dateString);
        const timeDiff = dueDate - now;
        return timeDiff > 0 && timeDiff < 24 * 60 * 60 * 1000;
    }

    // 更新Todo
    async function updateTodo(id, title, content, status) {
        try {
            const selectedTags = Array.from(document.querySelectorAll('#edit-selected-tags [data-tag-id]'))
                .map(el => parseInt(el.dataset.tagId));
            const requestData = {
                title: title,  // 确保标题被包含
                content: content,
                status: status,
                tagIds: selectedTags
            };
            const response = await fetch(`${state.apiBaseUrl}/todos/${id}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify(requestData)
            });

            if (!response.ok) {
                throw new Error('更新任务失败');
            }

            const updatedTodo = await response.json();
            // 更新本地列表
            const index = state.todos.findIndex(todo => todo.id === id);
            if (index !== -1) {
                state.todos[index] = updatedTodo;
            }
            applyFilter();
            showNotification('任务已更新');
            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error updating todo:', error);
            return false;
        }
    }

    // 添加Todo
    async function addTodo(title, content) {
        try {
            // 正确获取选中的标签ID
            const selectedTags = Array.from(document.querySelectorAll('#add-todo-tags [data-tag-id]'))
                .map(el => parseInt(el.dataset.tagId));

            // 获取到期时间
            const dueDate = document.getElementById('todo-due-date').value;

            const response = await fetch(`${state.apiBaseUrl}/todos`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify({
                    title: title,
                    content: content,
                    tagIds: selectedTags,
                    deadline: dueDate // 添加到期时间
                })
            });

            if (!response.ok) {
                throw new Error('添加任务失败');
            }

            const newTodo = await response.json();
            state.todos.unshift(newTodo);
            applyFilter();
            showNotification('任务已添加');

            // 清空表单和选中的标签
            document.getElementById('todo-title').value = '';
            document.getElementById('todo-content').value = '';
            document.getElementById('add-todo-tags').innerHTML = '';
            document.getElementById('todo-due-date').value = '';

            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error adding todo:', error);
            return false;
        }
    }

    // 切换待办状态
    async function toggleTodoStatus(id) {
        try {
            // 先获取当前todo
            const todo = state.todos.find(t => t.id === id);
            if (!todo) return false;

            // 切换状态
            const newStatus = todo.status === 'completed' ? 'pending' : 'completed';

            const response = await fetch(`${state.apiBaseUrl}/todos/${id}/status`, {
                method: 'PATCH',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify({ status: newStatus })
            });

            if (!response.ok) {
                throw new Error('更新状态失败');
            }

            // 更新本地状态
            const updatedTodo = await response.json();
            const index = state.todos.findIndex(t => t.id === id);
            if (index !== -1) {
                state.todos[index] = updatedTodo;
            }

            applyFilter();
            showNotification(`任务已${newStatus === 'completed' ? '标记为完成' : '标记为未完成'}`);
            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error toggling todo status:', error);
            return false;
        }
    }

    // 分享功能实现
    async function shareTodo(id) {
        try {
            const response = await fetch(`${state.apiBaseUrl}/todos/${id}/share`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${state.currentUser.token}`
                }
            });

            if (!response.ok) {
                throw new Error('生成分享链接失败');
            }

            const result = await response.json();
            const shareUrl = `${window.location.origin}/shared-todo.html?token=${result.shareToken}`;

            // 显示分享链接
            document.getElementById('share-link').value = shareUrl;
            document.getElementById('share-modal').classList.remove('hidden');

            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error sharing todo:', error);
            return false;
        }
    }

    // 获取所有用户（管理员功能）
    async function fetchAllUsers() {
        try {

            const response = await fetch(`${state.apiBaseUrl}/admin/users`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${state.currentUser.token}`,
                    'Content-Type': 'application/json', // 补充内容类型
                    'Accept': 'application/json' // 声明接受的响应类型
                }
            });
            if (!response.ok) throw new Error('获取用户列表失败');
            const users = await response.json();
            renderUsersList(users);
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }

    // 渲染用户列表
    function renderUsersList(users) {
        const container = document.getElementById('users-list');
        container.innerHTML = users.map(user => `
        <div class="flex justify-between items-center p-3 border rounded-md">
            <div>
                <span class="font-medium">${user.username}</span>
                <span class="ml-2 text-sm text-gray-500">ID: ${user.id}</span>
                ${!user.enabled ?
            '<span class="ml-2 px-2 py-0.5 bg-red-100 text-red-800 text-xs rounded">已拉黑</span>' : ''}
            </div>
            <button class="block-user-btn px-3 py-1 ${!user.enabled ? 'bg-green-600' : 'bg-red-600'} text-white rounded text-sm"
                    data-id="${user.id}">
                ${user.enabled ? '拉黑' : '解除拉黑'}
            </button>
        </div>
    `).join('');

        // 绑定拉黑按钮事件
        document.querySelectorAll('.block-user-btn').forEach(btn => {
            btn.addEventListener('click', async (e) => {
                const userId = parseInt(e.currentTarget.dataset.id);
                await toggleUserBlacklist(userId);
            });
        });
    }

    // 切换用户拉黑状态
    async function toggleUserBlacklist(userId) {
        try {
            const response = await fetch(`${state.apiBaseUrl}/admin/users/${userId}/blacklist`, {
                method: 'PATCH',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                }
            });

            if (!response.ok) throw new Error('操作失败');
            showNotification('操作成功');
            await fetchAllUsers(); // 重新加载用户列表
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }

    // 举报功能实现
    async function reportTodo(id, reason) {  // 增加id参数
        try {
            const response = await fetch(`${state.apiBaseUrl}/reports/${id}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify({
                    reason,
                    todoId: id  // 向后端传递todoId参数
                })
            });

            if (!response.ok) {
                const errorText = await response.text();
                throw new Error(`举报提交失败: ${errorText}`);
            }

            showNotification('举报已提交，感谢您的反馈');
            document.getElementById('report-modal').classList.add('hidden');
            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error reporting todo:', error);
            return false;
        }
    }

    // 回复功能实现
    async function replyToTodo(id, content, parentId = null) {
        try {
            const response = await fetch(`${state.apiBaseUrl}/comments`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser.token}`
                },
                body: JSON.stringify({
                    content,
                    userId: state.currentUser.userId,
                    todoId: id,  // 修改参数名从id为todoId，与后端保持一致
                    parentId: parentId || null
                })
            });

            if (!response.ok) {
                throw new Error('回复提交失败');
            }

            const newReply = await response.json();
            // 更新本地待办事项的回复
            const todoIndex = state.todos.findIndex(t => t.id === id);
            if (todoIndex !== -1) {
                if (!state.todos[todoIndex].replies) {
                    state.todos[todoIndex].replies = [];
                }

                // 如果是回复评论，找到对应的父评论并添加到其replies数组
                if (parentId) {
                    const addReplyToParent = (replies) => {
                        for (let reply of replies) {
                            if (reply.id === parentId) {
                                if (!reply.replies) reply.replies = [];
                                reply.replies.push(newReply);
                                return true;
                            }
                            if (reply.replies && addReplyToParent(reply.replies)) {
                                return true;
                            }
                        }
                        return false;
                    };
                    addReplyToParent(state.todos[todoIndex].replies);
                } else {
                    // 直接添加为顶级评论
                    state.todos[todoIndex].replies.push(newReply);
                }
                applyFilter();
            }

            showNotification('回复已添加');
            document.getElementById('reply-modal').classList.add('hidden');
            return true;
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('Error replying to todo:', error);
            return false;
        }
    }

    // 全局变量，存储标签ID到名称的映射
    let tagIdToName = {};

    // 加载用户标签时初始化映射
    async function loadUserTags() {
        if (!state.currentUser) return;

        try {
            const response = await fetch(`${state.apiBaseUrl}/tags/user`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${state.currentUser.token}`,
                    'Content-Type': 'application/json'
                }
            });

            if (!response.ok) throw new Error('获取标签失败');
            const tags = await response.json();
            state.userTags = tags;

            // 构建ID到名称的映射
            tagIdToName = {};
            tags.forEach(tag => {
                tagIdToName[tag.id] = tag.name;
            });

            renderAvailableTags();
        } catch (error) {
            console.error('标签加载错误:', error);
        }
    }
    // // 加载用户标签
    // async function loadUserTags() {
    //     if (!state.currentUser) return;
    //
    //     try {
    //         // 使用正确的API路径
    //         const response = await fetch(`${state.apiBaseUrl}/tags/user`, {
    //             method: 'GET',
    //             headers: {
    //                 'Authorization': `Bearer ${state.currentUser.token}`,
    //                 'Content-Type': 'application/json'
    //             }
    //         });
    //
    //         if (!response.ok) {
    //             const status = response.status;
    //             const allowHeader = response.headers.get('Allow');
    //             throw new Error(`获取标签失败 (${status})，服务器支持的方法: ${allowHeader}`);
    //         }
    //
    //         state.userTags = await response.json();
    //         renderAvailableTags();
    //         renderTagManagementList();
    //     } catch (error) {
    //         showNotification(error.message, 'error');
    //         console.error('标签加载错误:', error);
    //     }
    //     document.querySelectorAll('#add-todo-tags .tag-item').forEach(tag => {
    //         tag.addEventListener('click', function() {
    //             this.remove();
    //             // 放回可选标签列表
    //             const tagId = this.dataset.id;
    //             const tagName = this.dataset.name;
    //             const availableTagsContainer = document.getElementById('add-available-tags');
    //
    //             // 创建可选标签元素
    //             const availableTag = document.createElement('span');
    //             availableTag.className = 'px-2 py-1 bg-gray-100 rounded-md text-sm cursor-pointer hover:bg-gray-200';
    //             availableTag.dataset.id = tagId;
    //             availableTag.textContent = tagName;
    //             availableTag.addEventListener('click', function() {
    //                 addTagToSelected(this, 'add');
    //             });
    //
    //             availableTagsContainer.appendChild(availableTag);
    //         });
    //     });
    //     document.querySelectorAll('#edit-selected-tags .tag-item').forEach(tag => {
    //         tag.addEventListener('click', function() {
    //             this.remove();
    //             // 放回可选标签列表
    //             const tagId = this.dataset.id;
    //             const tagName = this.dataset.name;
    //             const availableTagsContainer = document.getElementById('add-available-tags');
    //
    //             // 创建可选标签元素
    //             const availableTag = document.createElement('span');
    //             availableTag.className = 'px-2 py-1 bg-gray-100 rounded-md text-sm cursor-pointer hover:bg-gray-200';
    //             availableTag.dataset.id = tagId;
    //             availableTag.textContent = tagName;
    //             availableTag.addEventListener('click', function() {
    //                 addTagToSelected(this, 'add');
    //             });
    //
    //             availableTagsContainer.appendChild(availableTag);
    //         });
    //     });
    //
    //
    // }
    // 获取公开的待办事项
    async function fetchPublicTodos() {
        try {
            const response = await fetch(`${state.apiBaseUrl}/todos/public`);
            if (!response.ok) throw new Error('获取公开待办事项失败');

            let publicTodos = await response.json();

            // 为每个公开待办事项获取所有评论（包括嵌套回复）
            for (let todo of publicTodos) {
                try {
                    const commentsResponse = await fetch(`${state.apiBaseUrl}/comments/todo/${todo.id}`);
                    if (commentsResponse.ok) {
                        todo.replies = await commentsResponse.json();
                    }
                } catch (error) {
                    console.error(`获取公开评论失败:`, error);
                    todo.replies = [];
                }
            }

            state.publicTodos = publicTodos;
            renderPublicTodoList(); // 重新渲染公开列表
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }
    // 渲染公开待办事项列表
    function renderPublicTodoList() {
        const publicTodoList = document.getElementById('public-todo-list');
        if (!publicTodoList) return;

        publicTodoList.innerHTML = '';

        if (state.publicTodos?.length === 0) {
            publicTodoList.innerHTML = '<p class="text-center p-4 text-gray-500">暂无公开的待办事项</p>';
            return;
        }

        state.publicTodos.forEach(todo => {
            // 复用现有渲染逻辑，调整权限相关按钮
            const todoItem = document.createElement('div');
            todoItem.className = 'border-b border-gray-200 p-4';

            // 渲染内容（复用现有todo的渲染逻辑，移除编辑/删除等私有操作按钮）
            const createdAt = new Date(todo.createdAt).toLocaleString();
            const displayTitle = todo.title || '无标题';

            let repliesHtml = '';
            if (todo.replies && todo.replies.length > 0) {
                repliesHtml = `
                <div class="mt-3 pl-4 border-l-2 border-gray-100">
                    ${renderComments(todo.replies)}
                </div>
            `;
            }

            todoItem.innerHTML = `
            <div class="flex justify-between items-start mb-2">
                <div class="flex items-center">
                    <span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">
                        公开
                    </span>
                    <span class="text-sm text-gray-500 ml-2">${createdAt}</span>
                </div>
            </div>
            <h3 class="text-gray-900 font-medium mb-1 ${todo.status === 'completed' ? 'line-through' : ''}">${displayTitle}</h3>
            <p class="text-gray-700 ${todo.status === 'completed' ? 'line-through text-gray-500' : ''}">${todo.content}</p>

            <!-- 标签显示 -->
            ${todo.tagIds && todo.tagIds.length > 0 ? `
            <div class="flex flex-wrap gap-1 mt-2">
                ${todo.tagIds.map(tagId => {
                const tagName = tagIdToName[tagId] || `未知标签(${tagId})`;
                return `
                    <span class="px-2 py-0.5 text-xs bg-blue-100 text-blue-800 rounded-full">
                        ${tagName}
                    </span>
                    `;
            }).join('')}
            </div>
            ` : ''}

            <!-- 回复区域 -->
            ${repliesHtml}

            <!-- 回复按钮 - 允许所有人评论 -->
            <button class="mt-2 text-sm text-blue-600 hover:text-blue-800 reply-btn" data-id="${todo.id}">
                <i class="fa fa-reply mr-1"></i> 添加回复
            </button>
        `;

            publicTodoList.appendChild(todoItem);
        });

        // 绑定评论相关事件
        bindPublicTodoEvents();
    }
    // 绑定公开待办事项的事件
    function bindPublicTodoEvents() {
        // 回复按钮事件
        document.querySelectorAll('.reply-btn').forEach(btn => {
            btn.addEventListener('click', handleReplyClick);
        });
    }


    // 添加选中的标签
    function addSelectedTag(tag, context = 'add') {
        const container = context === 'add'
            ? document.getElementById('add-todo-tags')
            : document.getElementById('edit-selected-tags');

        // 检查是否已添加
        if ([...container.children].some(el => el.dataset.tagId == tag.id)) {
            return;
        }

        const tagEl = document.createElement('div');
        // 关键修改：添加 tag-item 类名，确保选择器能匹配
        tagEl.className = 'tag-item px-2 py-1 bg-blue-100 text-blue-800 rounded text-sm flex items-center';
        tagEl.dataset.tagId = tag.id; // 确保使用 data-tag-id 属性
        tagEl.dataset.name = tag.name;
        tagEl.innerHTML = `
        ${tag.name}
        <button type="button" class="ml-1 text-blue-600 hover:text-blue-800">
            <i class="fa fa-times-circle"></i>
        </button>
    `;

        // 添加删除事件
        tagEl.querySelector('button').addEventListener('click', () => {
            tagEl.remove();
            // 恢复可选标签显示
            const availableContainer = context === 'add'
                ? document.getElementById('add-available-tags')
                : document.getElementById('edit-available-tags');
            const availableTag = availableContainer.querySelector(`[data-tag-id="${tag.id}"]`);
            if (availableTag) availableTag.style.display = 'inline-block';
        });

        container.appendChild(tagEl);
    }

    // 添加标签到已选列表的函数（修改版）
    function addTagToSelected(tagElement, type) {
        const tagId = tagElement.dataset.id;
        const tagName = tagElement.textContent;

        // 创建已选标签元素（带删除图标）
        const selectedTag = document.createElement('span');
        selectedTag.className = 'tag-item px-2 py-1 bg-blue-100 text-blue-800 rounded-md text-sm flex items-center cursor-pointer';
        selectedTag.dataset.id = tagId;
        selectedTag.dataset.name = tagName;
        selectedTag.innerHTML = `${tagName} <i class="fa fa-times ml-1"></i>`;

        // 关键：添加点击移除事件
        selectedTag.addEventListener('click', function(e) {
            e.stopPropagation(); // 防止事件冒泡
            this.remove(); // 从已选列表移除

            // 找到对应的可选标签并显示
            const availableTagsContainer = type === 'add'
                ? document.getElementById('add-available-tags')
                : document.getElementById('edit-available-tags');

            const availableTag = availableTagsContainer.querySelector(`[data-tag-id="${tagId}"]`);
            if (availableTag) {
                availableTag.style.display = 'inline-block'; // 显示标签
            }
        });

        // 添加到对应容器
        if (type === 'add') {
            document.getElementById('add-todo-tags').appendChild(selectedTag);
        } else {
            document.getElementById('edit-selected-tags').appendChild(selectedTag);
        }

        // 隐藏可选标签
        tagElement.style.display = 'none';
    }

    // 创建新标签 - 改进版
    document.getElementById('create-tag-btn')?.addEventListener('click', async () => {
        const tagInput = document.getElementById('new-tag-name');
        if (!tagInput) return; // 输入框不存在时直接返回

        const tagName = tagInput.value.trim();
        if (!tagName) {
            showNotification('请输入标签名称', 'error');
            tagInput.focus(); // 聚焦到输入框方便用户输入
            return;
        }

        // 简单验证标签名称长度
        if (tagName.length > 50) {
            showNotification('标签名称不能超过50个字符', 'error');
            tagInput.focus();
            return;
        }

        try {
            // 禁用按钮防止重复提交
            const createBtn = document.getElementById('create-tag-btn');
            createBtn.disabled = true;
            createBtn.textContent = '创建中...';

            const response = await fetch(`${state.apiBaseUrl}/tags`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${state.currentUser?.token}`
                },
                body: JSON.stringify({ name: tagName })
            });

            const result = await response.json(); // 解析响应内容

            if (!response.ok) {
                // 处理后端返回的具体错误信息
                throw new Error(result.message || '创建标签失败');
            }

            showNotification('标签创建成功');
            tagInput.value = '';
            await loadUserTags(); // 重新加载用户标签列表（原代码中是loadTags，根据上下文应该是loadUserTags）

        } catch (error) {
            showNotification(error.message, 'error');
            console.error('创建标签失败:', error);
        } finally {
            // 恢复按钮状态
            const createBtn = document.getElementById('create-tag-btn');
            if (createBtn) {
                createBtn.disabled = false;
                createBtn.innerHTML = '<i class="fa fa-plus"></i> 创建标签'; // 恢复原始内容
            }
        }
    });

    // 渲染标签管理列表
    function renderTagManagementList() {
        const container = document.getElementById('tag-list');
        if (!container) return;

        if (state.userTags && state.userTags.length > 0) {
            container.innerHTML = state.userTags.map(tag => `
        <div class="flex items-center px-2 py-1 bg-gray-100 rounded mb-1" data-tag-id="${tag.id}">
            <span class="flex-1">${tag.name}</span>
            <button class="text-blue-500 hover:text-blue-700 mr-2 edit-tag-btn"
                    onclick="editTag(${tag.id}, '${tag.name}')">
                <i class="fa fa-pencil"></i>
            </button>
            <button class="text-red-500 hover:text-red-700 delete-tag-btn">
                <i class="fa fa-trash"></i>
            </button>
        </div>
        `).join('');
        } else {
            container.innerHTML = '<p class="text-sm text-gray-500">暂无标签，点击"新标签"创建</p>';
        }
    }

    function editTag(tagId, currentName) {
        const newName = prompt('修改标签名称:', currentName);
        if (!newName || newName.trim() === currentName.trim()) return;

        updateTag(tagId, newName.trim());
    }

    async function updateTag(tagId, newName) {
        try {
            const response = await fetchWithToken(`${state.apiBaseUrl}/tags/${tagId}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ name: newName })
            });

            if (!response.ok) throw new Error('更新标签失败');

            // 更新本地标签列表
            state.userTags = state.userTags.map(tag =>
                tag.id === tagId ? { ...tag, name: newName } : tag
            );
            renderAvailableTags();
            renderTagManagementList();
            showNotification('标签已更新');
        } catch (error) {
            showNotification(error.message, 'error');
        }
    }

    // 检查过期和即将到期的任务
    function checkExpiringTodos() {
        const now = new Date();
        const upcomingThreshold = 24 * 60 * 60 * 1000; // 24小时内即将到期

        const expiringTodos = state.todos.filter(todo => {
            if (!todo.deadline || todo.status === 'completed') return false;

            const deadline = new Date(todo.deadline);
            const timeDiff = deadline - now;

            // 已过期或24小时内即将到期
            return timeDiff < 0 || (timeDiff > 0 && timeDiff < upcomingThreshold);
        });

        if (expiringTodos.length > 0) {
            showExpiringNotification(expiringTodos);
        }

        // 高亮显示过期和即将到期的任务
        highlightExpiringTodos();
    }

    // 显示即将到期通知
    function showExpiringNotification(todos) {
        const expired = todos.filter(t => new Date(t.deadline) < new Date());
        const upcoming = todos.filter(t => new Date(t.deadline) >= new Date());

        let message = '';
        if (expired.length > 0) {
            message += `有 ${expired.length} 个任务已过期\n`;
        }
        if (upcoming.length > 0) {
            message += `有 ${upcoming.length} 个任务将在24小时内到期`;
        }

        // 创建自定义弹窗
        const notification = document.createElement('div');
        notification.className = 'fixed top-20 left-1/2 transform -translate-x-1/2 bg-orange-50 border border-orange-200 text-orange-800 px-4 py-3 rounded-md shadow-lg z-50 flex items-center';
        notification.innerHTML = `
        <i class="fa fa-exclamation-circle mr-2 text-orange-500"></i>
        <div class="flex-1">
            <p class="font-medium">任务提醒</p>
            <p class="text-sm">${message}</p>
        </div>
        <button class="ml-4 text-orange-500 hover:text-orange-700 close-reminder">
            <i class="fa fa-times"></i>
        </button>
    `;

        document.body.appendChild(notification);

        // 关闭按钮事件
        notification.querySelector('.close-reminder').addEventListener('click', () => {
            notification.remove();
        });

        // 5秒后自动关闭
        setTimeout(() => {
            notification.remove();
        }, 5000);
    }

    // 高亮显示过期和即将到期的任务
    <!-- 更新高亮函数 -->
    function highlightExpiringTodos() {
        const now = new Date();
        const upcomingThreshold = 24 * 60 * 60 * 1000; // 24小时内

        document.querySelectorAll('#todos-list > div').forEach(el => {
            const todoId = parseInt(el.dataset.id);
            const todo = state.todos.find(t => t.id === todoId);

            if (!todo || todo.status === 'completed') {
                el.classList.remove('bg-red-50', 'bg-amber-50');
                return;
            }

            if (!todo.deadline) {
                el.classList.remove('bg-red-50', 'bg-amber-50');
                return;
            }

            const deadline = new Date(todo.deadline);
            const timeDiff = deadline - now;

            // 移除所有高亮类
            el.classList.remove('bg-red-50', 'bg-amber-50');

            // 添加相应高亮类
            if (timeDiff < 0) {
                // 已过期 - 红色背景
                el.classList.add('bg-red-50');
            } else if (timeDiff < upcomingThreshold) {
                // 即将到期 - 黄色背景
                el.classList.add('bg-amber-50');
            }
        });
    }

    // 定时检查任务到期情况
    function startExpirationChecker() {
        // 立即检查一次
        checkExpiringTodos();

        // 每小时检查一次
        setInterval(checkExpiringTodos, 3600000);
    }

    // 处理回复点击（支持楼中楼）
    function handleReplyClick(e) {
        const target = e.currentTarget;
        const todoId = parseInt(target.dataset.todoId || target.dataset.id);
        const parentId = target.dataset.parentId ? parseInt(target.dataset.parentId) : null;
        const replyToUser = target.dataset.replyTo;

        document.getElementById('reply-todo-id').value = todoId;
        document.getElementById('reply-parent-id').value = parentId || '';
        document.getElementById('reply-content').value = replyToUser ? `@${replyToUser} ` : '';

        // 更新模态框标题
        const modalTitle = document.getElementById('reply-modal-title');
        modalTitle.textContent = replyToUser ? `回复 @${replyToUser}` : '添加回复';

        document.getElementById('reply-modal').classList.remove('hidden');
    }

    // 添加渲染评论的函数
    function renderComments(comments) {
        return comments.map(comment => {
            // 格式化日期
            const commentDate = new Date(comment.createdAt).toLocaleString();

            // 递归渲染子评论（楼中楼）
            let subReplies = '';
            if (comment.replies && comment.replies.length > 0) {
                subReplies = `
                <div class="mt-2 pl-4 border-l-2 border-gray-100">
                    ${renderComments(comment.replies)}
                </div>
            `;
            }

            // 直接从评论对象获取username，不存在则显示匿名
            const username = comment.username || '匿名用户';

            return `
            <div class="mb-3">
                <div class="flex items-center mb-1">
                    <span class="text-sm font-medium text-gray-900">${username}</span>
                    <span class="text-xs text-gray-500 ml-2">${commentDate}</span>
                </div>
                <p class="text-sm text-gray-700">${comment.content}</p>
                <button class="text-xs text-blue-600 mt-1 reply-btn"
                        data-todo-id="${comment.todoId}"
                        data-parent-id="${comment.id}">
                    回复
                </button>
                ${subReplies}
            </div>
        `;
        }).join('');
    }


    // 事件绑定
    function bindTodoEvents() {
        // 状态切换按钮事件
        document.querySelectorAll('.status-toggle-btn').forEach(btn => {
            btn.addEventListener('click', async (e) => {
                const id = parseInt(e.currentTarget.dataset.id);
                await toggleTodoStatus(id);
            });
        });

        // 分享按钮事件
        document.querySelectorAll('.share-todo-btn').forEach(btn => {
            btn.addEventListener('click', async (e) => {
                const id = parseInt(e.currentTarget.dataset.id);
                await shareTodo(id);
            });
        });

        // 编辑按钮事件
        document.querySelectorAll('.edit-todo-btn').forEach(btn => {
            btn.addEventListener('click', handleEditClick);
        });

        // 删除按钮事件
        document.querySelectorAll('.delete-todo-btn').forEach(btn => {
            btn.addEventListener('click', handleDeleteClick);
        });

        // 举报按钮事件
        document.querySelectorAll('.report-todo-btn').forEach(btn => {
            btn.addEventListener('click', handleReportClick);
        });

        // 回复按钮事件
        document.querySelectorAll('.reply-btn').forEach(btn => {
            btn.addEventListener('click', handleReplyClick);
        });

        // 复制链接按钮事件
        document.getElementById('copy-link').addEventListener('click', () => {
            const linkInput = document.getElementById('share-link');
            linkInput.select();
            document.execCommand('copy');
            showNotification('链接已复制到剪贴板');
        });

        // 关闭分享模态框
        document.getElementById('close-share').addEventListener('click', () => {
            document.getElementById('share-modal').classList.add('hidden');
        });
    }

    // 用户登出
    function logout() {
        localStorage.removeItem('token');
        localStorage.removeItem('username');
        localStorage.removeItem('userId');
        state.currentUser = null;
        state.todos = [];
        state.filteredTodos = [];
        renderAuthState();
        showNotification('已退出登录');
    }

    // 事件监听器设置
    function setupEventListeners() {
        // 认证相关
        document.getElementById('login-btn').addEventListener('click', () => {
            window.location.href = '/login.html';
        });
        document.getElementById('register-btn').addEventListener('click', () => {
            window.location.href = '/register.html';
        });
        document.getElementById('login-btn-main').addEventListener('click', () => {
            window.location.href = '/login.html';
        });
        document.getElementById('register-btn-main').addEventListener('click', () => {
            window.location.href = '/register.html';
        });
        document.getElementById('logout-button').addEventListener('click', logout);

        // 复制分享链接
        document.getElementById('copy-link').addEventListener('click', () => {
            const input = document.getElementById('share-link');
            input.select();
            document.execCommand('copy');
            showNotification('链接已复制');
        });

        // 关闭模态框
        document.getElementById('close-share').addEventListener('click', () => {
            document.getElementById('share-modal').classList.add('hidden');
        });
        document.getElementById('cancel-edit').addEventListener('click', () => {
            document.getElementById('edit-modal').classList.add('hidden');
        });
        document.getElementById('cancel-delete').addEventListener('click', () => {
            document.getElementById('delete-modal').classList.add('hidden');
        });
        document.getElementById('cancel-report').addEventListener('click', () => {
            document.getElementById('report-modal').classList.add('hidden');
        });
        document.getElementById('cancel-reply').addEventListener('click', () => {
            document.getElementById('reply-modal').classList.add('hidden');
        });

        // 确认删除 - 修复删除功能
        document.getElementById('confirm-delete').addEventListener('click', async () => {
            const id = parseInt(document.getElementById('delete-todo-id').value);
            if (isNaN(id)) {
                showNotification('无效的任务ID', 'error');
                return;
            }

            try {
                const response = await fetch(`${state.apiBaseUrl}/todos/${id}`, {
                    method: 'DELETE',
                    headers: {
                        'Authorization': `Bearer ${state.currentUser.token}`
                    }
                });

                if (!response.ok) {
                    const errorText = await response.text();
                    throw new Error(errorText || '删除失败');
                }

                // 从本地状态中移除
                state.todos = state.todos.filter(todo => todo.id !== id);
                applyFilter();
                document.getElementById('delete-modal').classList.add('hidden');
                showNotification('任务已成功删除');
            } catch (error) {
                showNotification(error.message, 'error');
                console.error('Error deleting todo:', error);
            }
        });

        // 确认举报
        document.getElementById('confirm-report').addEventListener('click', async () => {
            const id = parseInt(document.getElementById('report-todo-id').value);
            const reason = document.getElementById('report-reason').value.trim();

            if (!reason) {
                showNotification('请输入举报原因', 'error');
                return;
            }

            await reportTodo(id, reason);
        });

        // 确认回复
        document.getElementById('confirm-reply').addEventListener('click', async () => {
            const todoId = parseInt(document.getElementById('reply-todo-id').value);
            const parentId = document.getElementById('reply-parent-id').value
                ? parseInt(document.getElementById('reply-parent-id').value)
                : null;
            const content = document.getElementById('reply-content').value.trim();

            if (!content) {
                showNotification('请输入回复内容', 'error');
                return;
            }

            await replyToTodo(todoId, content, parentId);
        });

        // 表单提交
        const addTodoForm = document.getElementById('add-todo-form');
        addTodoForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            // 获取表单值（保持标题和内容的必填验证）
            const title = document.getElementById('todo-title').value.trim();
            const content = document.getElementById('todo-content').value.trim();
            const dueDate = document.getElementById('todo-due-date').value;
            const status = document.getElementById('todo-status').value;

            // 验证标题和内容（这两项是核心必填项）
            if (!title) {
                showNotification('请输入任务标题', 'error');
                return;
            }

            if (!content) {
                showNotification('请输入任务内容', 'error');
                return;
            }

            // 获取已选标签（修改版）
            const selectedTags = [];
            // 关键修改：使用 data-tag-id 匹配属性，与生成时保持一致
            document.querySelectorAll('#add-todo-tags .tag-item').forEach(tag => {
                // 从 data-tag-id 获取值（之前可能错用了 data-id）
                selectedTags.push(parseInt(tag.dataset.tagId));
            });

            // 构建待办事项数据（标签可选）
            const todoData = {
                title,
                content,
                status,
                deadline: dueDate || null,
                tagIds: selectedTags // 允许为空数组
            };

            try {
                // 提交表单数据
                const response = await fetchWithToken(`${state.apiBaseUrl}/todos`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(todoData)
                });

                if (!response.ok) throw new Error('添加任务失败');

                showNotification('任务添加成功');
                this.reset();
                document.getElementById('add-todo-tags').innerHTML = ''; // 清空选中标签
                await fetchTodos(); // 刷新列表
            } catch (error) {
                showNotification(error.message, 'error');
            }
        });

        document.getElementById('edit-todo-form').addEventListener('submit', async function(e) {
            e.preventDefault();

            const id = document.getElementById('edit-todo-id').value;
            const title = document.getElementById('edit-todo-title').value.trim();
            const content = document.getElementById('edit-todo-content').value.trim();
            const dueDate = document.getElementById('edit-todo-due-date').value;
            const status = document.getElementById('edit-todo-status').value;

            // 验证标题和内容（核心必填项）
            if (!title) {
                showNotification('请输入任务标题', 'error');
                return;
            }

            if (!content) {
                showNotification('请输入任务内容', 'error');
                return;
            }

            // 获取已选标签（编辑场景）
            const selectedTags = [];
            document.querySelectorAll('#edit-selected-tags .tag-item').forEach(tag => {
                selectedTags.push(parseInt(tag.dataset.tagId)); // 统一使用 data-tag-id
            });

            const todoData = {
                title,
                content,
                status,
                deadline: dueDate || null,
                tagIds: selectedTags // 允许为空数组
            };

            try {
                const response = await fetchWithToken(`${state.apiBaseUrl}/todos/${id}`, {
                    method: 'PUT',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(todoData)
                });

                if (!response.ok) throw new Error('更新任务失败');

                showNotification('任务更新成功');
                document.getElementById('edit-modal').classList.add('hidden');
                await fetchTodos();
            } catch (error) {
                showNotification(error.message, 'error');
            }
        });

        // 筛选按钮
        elements.filterButtons.all.addEventListener('click', () => {
            state.currentFilter = 'all';
            updateFilterButtons();
            applyFilter();
        });
        elements.filterButtons.pending.addEventListener('click', () => {
            state.currentFilter = 'pending';
            updateFilterButtons();
            applyFilter();
        });
        elements.filterButtons.completed.addEventListener('click', () => {
            state.currentFilter = 'completed';
            updateFilterButtons();
            applyFilter();
        });

        // 滚动时改变导航栏样式
        window.addEventListener('scroll', () => {
            const navbar = document.getElementById('navbar');
            if (window.scrollY > 10) {
                navbar.classList.add('py-2');
                navbar.classList.remove('py-3');
            } else {
                navbar.classList.add('py-3');
                navbar.classList.remove('py-2');
            }
        });
    }

    // 更新筛选按钮样式
    function updateFilterButtons() {
        Object.values(elements.filterButtons).forEach(btn => {
            btn.classList.remove('bg-primary', 'text-white');
            btn.classList.add('bg-gray-200', 'text-gray-700', 'hover:bg-gray-300');
        });
        elements.filterButtons[state.currentFilter].classList.remove('bg-gray-200', 'text-gray-700', 'hover:bg-gray-300');
        elements.filterButtons[state.currentFilter].classList.add('bg-primary', 'text-white');
    }

    // 检查到期任务并提醒
    <!-- 更新提醒函数 -->
    function checkDueTasks() {
        const now = new Date();
        const upcomingThreshold = 24 * 60 * 60 * 1000; // 24小时内
        const upcomingTasks = state.todos.filter(todo => {
            if (!todo.deadline || todo.status === 'completed') return false;
            const dueDate = new Date(todo.deadline);
            const timeDiff = dueDate - now;
            return timeDiff > 0 && timeDiff < upcomingThreshold;
        });

        const expiredTasks = state.todos.filter(todo => {
            if (!todo.deadline || todo.status === 'completed') return false;
            return new Date(todo.deadline) < now;
        });

        if (expiredTasks.length > 0) {
            showNotification(`有 ${expiredTasks.length} 个任务已过期`, 'error');
        }

        if (upcomingTasks.length > 0) {
            showNotification(`有 ${upcomingTasks.length} 个任务即将在24小时内到期`, 'info');
        }
    }

    // 定时检查到期任务
    setInterval(checkDueTasks, 3600000); // 每小时检查一次

    // 初始化应用
    function init() {
        setupEventListeners();
        checkAuth();
        setupTokenChecker();
        fetchPublicTodos();
    }

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', init);

    // 处理Excel导入（与导出格式匹配）
    document.getElementById('import-todos').addEventListener('change', async (e) => {
        const file = e.target.files[0];
        if (!file) return;

        // 创建FormData对象，用于文件上传
        const formData = new FormData();
        formData.append('file', file);

        try {
            // 直接发送文件给后端，由后端解析Excel内容
            const response = await fetch(`${state.apiBaseUrl}/todos/import`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${state.currentUser.token}`
                    // 不要设置Content-Type，浏览器会自动添加正确的multipart/form-data头
                },
                body: formData
            });

            if (!response.ok) {
                const error = await response.text();
                throw new Error(error || '导入失败');
            }

            const result = await response.json();
            showNotification(`成功导入 ${result.importedCount} 条任务`);
            await fetchTodos(); // 重新加载任务列表
            e.target.value = ''; // 重置文件输入
        } catch (error) {
            showNotification(error.message, 'error');
            console.error('导入失败:', error);
        }
    });

    // 辅助函数：检查两个数组是否相等
    function arraysMatch(arr1, arr2) {
        if (arr1.length !== arr2.length) return false;
        return arr1.every((val, index) => val === arr2[index]);
    }

    // 辅助函数：解析多种格式的日期字符串
    function parseDate(dateStr) {
        if (!dateStr) return null;

        // 尝试多种常见日期格式
        const formats = [
            'yyyy-MM-dd HH:mm:ss',
            'yyyy/MM/dd HH:mm:ss',
            'yyyy年MM月dd日 HH:mm:ss',
            'yyyy-MM-dd',
            'yyyy/MM/dd',
            'yyyy年MM月dd日'
        ];

        for (const format of formats) {
            try {
                // 使用日期库或自定义解析逻辑
                const date = new Date(dateStr);
                if (!isNaN(date.getTime())) {
                    return date.toISOString(); // 转换为ISO格式供后端处理
                }
            } catch (e) {
                continue;
            }
        }

        console.warn(`无法解析日期格式: ${dateStr}`);
        return null;
    }

    // 处理Excel导出
    document.getElementById('export-todos').addEventListener('click', async () => {
        try {
            // 准备导出数据
            const exportData = state.todos.map(todo => ({
                标题: todo.title,
                内容: todo.content,
                状态: todo.status === 'completed' ? '已完成' : '待完成',
                创建时间: new Date(todo.createdAt).toLocaleString(),
                到期时间: todo.deadline ? new Date(todo.deadline).toLocaleString() : ''
            }));

            // 创建工作簿和工作表
            const worksheet = XLSX.utils.json_to_sheet(exportData);
            const workbook = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(workbook, worksheet, '待办事项');

            // 生成并下载文件
            XLSX.writeFile(workbook, `待办事项_${new Date().toLocaleDateString()}.xlsx`);
            showNotification('导出成功');
        } catch (error) {
            showNotification('导出失败', 'error');
            console.error('导出失败:', error);
        }
    });

    // 管理员中心按钮
    document.getElementById('admin-center-btn')?.addEventListener('click', () => {
        if (state.currentUser?.isAdmin) {
            elements.adminView.classList.toggle('hidden');
        }
    });

    // 管理用户按钮
    document.getElementById('manage-users-btn')?.addEventListener('click', () => {
        if (state.currentUser?.isAdmin) {
            document.getElementById('user-management-modal').classList.remove('hidden');
            fetchAllUsers(); // 获取用户列表
        }
    });

    // 关闭用户管理模态框
    document.getElementById('close-user-modal')?.addEventListener('click', () => {
        document.getElementById('user-management-modal').classList.add('hidden');
    });

    // 页面加载时检查
    document.addEventListener('DOMContentLoaded', () => {
        // 检查是否有登录状态
        const token = localStorage.getItem('token');
        if (token) {
            // 加载用户信息后加载标签
            loadUserInfo().then(() => {
                loadUserTags();
            });
        }
    });
</script>
</body>
</html>